﻿namespace InfluxDBClient;

public class ApiExtension : ICanByApi
{
    private readonly string _url;
    private readonly string _org;
    private readonly string _bucket;
    private readonly string _token;
    private readonly string _precision;

    

    /// <summary>
    /// 查询\写入初始换
    /// </summary>
    /// <param name="url">ip+port</param>
    /// <param name="orgId">org</param>
    /// <param name="token">token</param>
    /// <param name="precision">时间精度 ms毫秒ns纳秒</param>
    /// <param name="bucket">bucket</param>
    public ApiExtension(string url, string orgId, string token, string bucket, string precision="ms")
    {
        _url = url;
        _org = orgId;
        _token = token;
        _precision = precision;
        _bucket = bucket;
    }

    public async Task<string> Write(IEnumerable<string> lines)
    {
        var client = new HttpClient();
        var line = string.Join("\n\r", lines);
        var request = new HttpRequestMessage
        {
            Method = HttpMethod.Post,
            RequestUri = new Uri($"http://{_url}/api/v2/write?org={_org}&bucket={_bucket}&precision={_precision}"),
            Headers =
            {
                {"Authorization", $"Token {_token}"},
                {"Accept", "application/json"},
            },

            Content = new StringContent(line)
            {
                Headers =
                {
                    ContentType = new MediaTypeHeaderValue("text/plain")
                }
            }
        };
        using var response = await client.SendAsync(request);
        response.EnsureSuccessStatusCode();
        var body = await response.Content.ReadAsStringAsync();
        Console.WriteLine(body);
        return body;
    }
    
    public async Task<string> Write(string measurement,IEnumerable<(string tag, double val, string ts)> items)
    {
        var lines = from i in items
            select $"{measurement},tag={i.tag} _value={i.val} {i.ts}";
        var client = new HttpClient();
        var line = string.Join("\n\r", lines);
        var request = new HttpRequestMessage
        {
            Method = HttpMethod.Post,
            RequestUri = new Uri($"http://{_url}/api/v2/write?org={_org}&bucket={_bucket}&precision={_precision}"),
            Headers =
            {
                {"Authorization", $"Token {_token}"},
                {"Accept", "application/json"},
            },

            Content = new StringContent(line)
            {
                Headers =
                {
                    ContentType = new MediaTypeHeaderValue("text/plain")
                }
            }
        };
        using var response = await client.SendAsync(request);
        response.EnsureSuccessStatusCode();
        var body = await response.Content.ReadAsStringAsync();
        Console.WriteLine(body);
        return body;
    }

    public List<(string tag, double val, string ts)> Query(string script)
    {
        var csv = QueryByWebApi(script).Result;
        var lines = csv.Trim().Split("\r\n");
        var data = lines.Skip(1).Take(lines.Length - 1);
        var parOptions = new ParallelOptions
        {
            MaxDegreeOfParallelism = 4
        };
        var headerLine = lines.First().Split(',').ToList();
        var tagIndex = headerLine.IndexOf("tag");
        var valueIndex = headerLine.IndexOf("_value");
        var tsIndex = headerLine.IndexOf("_time");
        if (tsIndex==-1)
        {
            tsIndex=  headerLine.IndexOf("_start");
        }
        if (tsIndex==-1)
        {
            tsIndex= headerLine.IndexOf("_stop");
        }
        ConcurrentBag<(string tag, double val, string date)> concurrentBag =
            new ConcurrentBag<(string tag, double val, string ts)>();
        Parallel.ForEach(data, parOptions, (line, _) =>
        {
            var items = line.Split(',');
            concurrentBag.Add(new ValueTuple<string, double, string>(items[tagIndex], double.Parse(items[valueIndex]),
                items[tsIndex]));
        });
        return concurrentBag.ToList();
    }

    private async Task<string> QueryByWebApi(string flux)
    {
        var client = new HttpClient();
        var request = new HttpRequestMessage
        {
            Method = HttpMethod.Post,
            RequestUri = new Uri($"http://{_url}/api/v2/query?org={_org}"),
            Headers =
            {
                {"Authorization", $"Token {_token}"},
                {"Accept", "application/csv"},
                {"Accept-Encoding", "gzip,deflate"},
            },
            Content = new StringContent(flux)
            {
                Headers =
                {
                    ContentType = new MediaTypeHeaderValue("application/vnd.flux")
                }
            }
        };
        using var response = await client.SendAsync(request);
        response.EnsureSuccessStatusCode();
        if (Equals("gzip", response.Content.Headers.ContentEncoding.ToString()))
        {
            Stream getStream = new System.IO.Compression.GZipStream(await response.Content.ReadAsStreamAsync(),
                System.IO.Compression.CompressionMode.Decompress);
            var sr = new StreamReader(getStream, Encoding.UTF8);
            var body = await sr.ReadToEndAsync();
            return body;
        }

        return await response.Content.ReadAsStringAsync();
    }
}